/*
 *Copyright (c) [2019-2020]  C2comm, Inc.  All rights reserved.
 *
 *This program is free software; you can redistribute it and/or
 *modify it under the terms of the GNU General Public License
 *as published by the Free Software Foundation; either version 2
 *of the License, or (at your option) any later version.
 *
 *This program is distributed in the hope that it will be useful,
 *but WITHOUT ANY WARRANTY; without even the implied warranty of
 *MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *GNU General Public License for more details.
 *
 *You should have received a copy of the GNU General Public License
 *along with this program; If not, see <https://www.gnu.org/licenses/>
 */

/*
 *Vendor: C2comm
 *Version: 1.0
 *Filename: CMUnsync.v
 *Target Device: Altera
 *Author : 刘晓骏
*/

module CMUnsync(
    input  wire       SYS2CORE_clk,
    input  wire       SYS2CORE_rst_n,
    
    input  wire       GA2CU_guard_state_cs,
    
    input  wire       GA2CU_guard_pcf_valid,
    input  wire [3:0] GA2CU_guard_pcf,
    output wire       CU2GA_guard_pcf_ready,
    
    output reg        CU2CS_cmd_valid,
    output reg  [5:0] CU2CS_cmd_next_top_state,
    output wire [5:0] CU2CS_cmd_bottom_state
);
/*//////////////////////////////////////////////////////////
                    中间变量声明区域
*///////////////////////////////////////////////////////////
//本模块中所有中间变量(wire/reg/parameter)在此集中声明 
reg [5:0] next_cu_state;
reg [5:0] curr_cu_state;

localparam CM_INTEGRATE  = 6'b000001,
           CM_UNSYNC     = 6'b000010,
           CM_CA_ENABLED = 6'b000100,
           CM_WAIT_4_IN  = 6'b001000,
           CM_SYNC       = 6'b010000,
           CM_STABLE     = 6'b100000;
           
localparam INIT_S     = 6'b000001,
           MATCH_S    = 6'b000010,
           COMPLETE_S = 6'b000100,
           C0_S       = 6'b001000,
           C1_S       = 6'b010000,
           C2_S       = 6'b100000;
/*//////////////////////////////////////////////////////////
                    状态机跳转处理
*///////////////////////////////////////////////////////////
assign CU2CS_cmd_bottom_state = next_cu_state;
//使用组合逻辑的next_cu_state实时生成ready信号
//从而防止出现在MATCH_S状态触发了往下个状态跳转的信号，但ready要到下个周期才会置0的问题
assign CU2GA_guard_pcf_ready = (next_cu_state == MATCH_S);


//根据当前状态和输入条件来决定下一跳的状态
//采用三段式实现状态机，使得编写逻辑时可以方便使用组合逻辑部分作为条件以规避时序逻辑带来的1个周期的延时
always @* begin
    case(curr_cu_state)
        INIT_S: begin
            if(GA2CU_guard_state_cs == 1'b1)
                next_cu_state = MATCH_S;
            else
                next_cu_state = INIT_S;
        end
        
        MATCH_S: begin
            if((GA2CU_guard_pcf_valid == 1'b1) && 
               (GA2CU_guard_pcf[1:0] == 2'd0))
                next_cu_state = C0_S;
            else if((GA2CU_guard_pcf_valid == 1'b1) && 
                    (GA2CU_guard_pcf[1:0] == 2'd1) && 
                    (GA2CU_guard_pcf[2] == 1'b1))
                next_cu_state = C1_S;
            else if((GA2CU_guard_pcf_valid == 1'b1) && 
                    (GA2CU_guard_pcf[1:0] == 2'd2) && 
                    (GA2CU_guard_pcf[3] == 1'b1))
                next_cu_state = C2_S;
            else
                next_cu_state = MATCH_S;
        end
        
        C0_S: begin
            next_cu_state = COMPLETE_S;
        end
        
        C1_S: begin
            next_cu_state = COMPLETE_S;
        end
        
        C2_S: begin
            next_cu_state = COMPLETE_S;
        end
        
        COMPLETE_S: begin
            next_cu_state = INIT_S;
        end
        
        default: next_cu_state = INIT_S;
    endcase
end

//时序逻辑用于缓存当前状态
always @(posedge SYS2CORE_clk or negedge SYS2CORE_rst_n) begin
    if(SYS2CORE_rst_n == 1'b0) begin
        curr_cu_state <= INIT_S;
    end
    else begin
        curr_cu_state <= next_cu_state;
    end
end

//在该时序逻辑部分实现各状态的执行动作
always @(posedge SYS2CORE_clk or negedge SYS2CORE_rst_n) begin
    if(SYS2CORE_rst_n == 1'b0) begin
        CU2CS_cmd_valid <= 1'b0;
        CU2CS_cmd_next_top_state <= 6'b0;
    end
    else begin
        case(curr_cu_state)
            INIT_S: begin
                CU2CS_cmd_valid <= 1'b0;
                CU2CS_cmd_next_top_state <= 6'b0;
            end
            
            MATCH_S:begin
                CU2CS_cmd_valid <= 1'b0;
                CU2CS_cmd_next_top_state <= 6'b0;
            end
            
            C0_S:begin
                CU2CS_cmd_valid <= 1'b1;
                CU2CS_cmd_next_top_state <= CM_CA_ENABLED;
            end
            
            C1_S:begin
                CU2CS_cmd_valid <= 1'b1;
                CU2CS_cmd_next_top_state <= CM_CA_ENABLED;
            end
            
            C2_S:begin
                CU2CS_cmd_valid <= 1'b1;
                CU2CS_cmd_next_top_state <= CM_SYNC;
            end
            
            COMPLETE_S:begin
                CU2CS_cmd_valid <= 1'b0;
                CU2CS_cmd_next_top_state <= 6'b0;
            end
            
            default: begin
                CU2CS_cmd_valid <= 1'b0;
                CU2CS_cmd_next_top_state <= 6'b0;
            end
        endcase
    end
end
/*//////////////////////////////////////////////////////////
                   IP调用区域
*///////////////////////////////////////////////////////////
//本模块调用的所有IP在该区域实例化
//例如fifo/ram/grant之类的IP....   
endmodule
/*
CMUnsync CMUnsync_inst(
    .SYS2CORE_clk(),
    .SYS2CORE_rst_n(),

    .GA2CU_guard_state_cs(),

    .GA2CU_guard_pcf_valid(),
    .GA2CU_guard_pcf(),
    .CU2GA_guard_pcf_ready(),


    .CU2CS_cmd_valid(),
    .CU2CS_cmd_next_top_state(),
    .CU2CS_cmd_bottom_state()
);
*/